#include "HardwareProfile.h"
#include "RTCC.h"
//#include "BCDTimeOP.h"
/*****************************************************************************
 * Structures: rtccTime and rtccTime_chk
 *
 * Overview: These structures contain the time and date.
 * RTCCProcessEvents updates them. rtccTime_chk is used as input/output for
 * get/set operations.
 *
 *****************************************************************************/
RTCC rtccTime,rtccTimeInner;

/*****************************************************************************
 * Function: RTCCInit
 *
 * Preconditions: RTCCInit must be called before.
 *
 * Overview: Enable the oscillator for the RTCC
 *
 * Input: None.
 *
 * Output: None.
 *****************************************************************************/
void RTCCInit(void)
{
    // Set the RTCC to a default value, and start it.
    RCFGCAL = 0x0000;
	RTCCUnlock();                                           // Unlock the RTCC
//    __builtin_write_RTCWEN();
    RCFGCALbits.RTCEN = 1;	
}
/*****************************************************************************
 * Function: RTCCUnlock
 *
 * Preconditions: None.
 *
 * Overview: The function allows a writing into the clock registers.
 *
 * Input: None.
 *
 * Output: None.
 *
 *****************************************************************************/
void RTCCUnlock(void)
{

    asm volatile("disi	#5");
    asm volatile("mov	#0x55, w7");
    asm volatile("mov	w7, _NVMKEY");
    asm volatile("mov	#0xAA, w8");
    asm volatile("mov	w8, _NVMKEY");

    //	asm volatile("bset	_NVMCON, #15");
    asm volatile("bset	_RCFGCAL, #13");
    asm volatile("nop");
    asm volatile("nop");


    //	EECON2 = 0x55;
    //	EECON2 = 0xAA;
    RCFGCALbits.RTCWREN = 1;
}

/*****************************************************************************
 * Function: RTCCSetTime
 *
 * Preconditions: None.
 *
 * Overview: The function upload time and date from rtccTime_chk into clock.
 *
 * Input: rtccTime_chk - structure containing time and date.
 *
 * Output: None.
 *
 *****************************************************************************/
void RTCCSetTime()
{
	RTCCUnlock();           // Unlock the RTCC
    // Set the time
    RCFGCALbits.RTCPTR = 0;
    RTCVAL = rtccTimeInner.prt00;
    RCFGCALbits.RTCPTR = 1;
    RTCVAL = rtccTimeInner.prt01;
    RCFGCALbits.RTCPTR = 2;
    RTCVAL = rtccTimeInner.prt10;
    RCFGCALbits.RTCPTR = 3;
    RTCVAL = rtccTimeInner.prt11;
    RTCCLock();         // Lock the RTCC    
}
void RTCCGetTime(void) 
{
	RTCC rtccTime_chk;
	while(1)
	{
		RCFGCALbits.RTCPTR = 0;
		rtccTime.prt00 = RTCVAL;
		RCFGCALbits.RTCPTR = 1;
		rtccTime.prt01 = RTCVAL;
		RCFGCALbits.RTCPTR = 2;
		rtccTime.prt10 = RTCVAL;
		RCFGCALbits.RTCPTR = 3;
		rtccTime.prt11 = RTCVAL;

		// Grab the time again
		RCFGCALbits.RTCPTR = 0;
		rtccTime_chk.prt00 = RTCVAL;
		RCFGCALbits.RTCPTR = 1;
		rtccTime_chk.prt01 = RTCVAL;
		RCFGCALbits.RTCPTR = 2;
		rtccTime_chk.prt10 = RTCVAL;
		RCFGCALbits.RTCPTR = 3;
		rtccTime_chk.prt11 = RTCVAL;

		// Verify there is no roll-over
		if ((rtccTime.prt00 == rtccTime_chk.prt00) &&
			(rtccTime.prt01 == rtccTime_chk.prt01) &&
			(rtccTime.prt10 == rtccTime_chk.prt10) &&
			(rtccTime.prt11 == rtccTime_chk.prt11))
			break;
	}	
}


/*****************************************************************************
 * Function: RTCCSetBinSec
 *
 * Preconditions: None.
 *
 * Overview: The function verifies setting seconds range, translates it into
 * BCD format and writes into rtccTime_chk structure. To write the structure into
 * clock RTCCSetTime must be called.
 *
 * Input: Seconds binary value.
 *
 * Output: Checked BCD value in rtccTime_chk structure.
 *
 *****************************************************************************/
void RTCCSetBinSec(unsigned char Sec)
{
    if(Sec == 0xff) Sec = 59;
    if(Sec == 60)   Sec = 0;
    RTCCSetSec(RTCCBin2Dec(Sec));
}

/*****************************************************************************
 * Function: RTCCSetBinMin
 *
 * Preconditions: None.
 *
 * Overview: The function verifies a setting minutes range, translates it into
 * BCD format and writes into rtccTime_chk structure. To write the structure into
 * clock RTCCSetTime must be called.
 *
 * Input: Minutes binary value.
 *
 * Output: Checked BCD value in rtccTime_chk structure.
 *
 *****************************************************************************/
void RTCCSetBinMin(unsigned char Min)
{
    if(Min == 0xff) Min = 59;
    if(Min == 60)   Min = 0;
    RTCCSetMin(RTCCBin2Dec(Min));
}

/*****************************************************************************
 * Function: RTCCSetBinHour
 *
 * Preconditions: None.
 *
 * Overview: The function verifies a setting hours range, translates it into
 * BCD format and writes into rtccTime_chk structure. To write the structure into
 * clock RTCCSetTime must be called.
 *
 * Input: Hours binary value.
 *
 * Output: Checked BCD value in rtccTime_chk structure.
 *
 *****************************************************************************/
void RTCCSetBinHour(unsigned char Hour)
{
    if(Hour == 0xff) Hour = 23;
    if(Hour == 24)   Hour = 0;
    RTCCSetHour(RTCCBin2Dec(Hour));
}

/*****************************************************************************
 * Function: RTCCCalculateWeekDay
 *
 * Preconditions: Valid values of day, month and year must be presented in
 * rtccTime_chk structure.
 *
 * Overview: The function reads day, month and year from rtccTime_chk and
 * calculates week day. Than It writes result into rtccTime_chk. To write
 * the structure into clock RTCCSetTime must be called.
 *
 * Input: rtccTime_chk with valid values of day, month and year.
 *
 * Output: Zero based week day in rtccTime_chk structure.
 *
 *****************************************************************************/
#ifdef RTCCCALCULATEWEEKDAY
void RTCCCalculateWeekDay()
{
	const char MonthOffset[] =
		//jan feb mar apr may jun jul aug sep oct nov dec
	{   0,  3,  3,  6,  1,  4,  6,  2,  5,  0,  3,  5 };
	unsigned Year;
	unsigned Month;
	unsigned Day;
	unsigned Offset;

	// calculate week day
	Year  = RTCCGetBinYear();
	Month = RTCCGetBinMonth();
	Day  = RTCCGetBinDay();

	// 2000s century offset = 6 +
	// every year 365%7 = 1 day shift +
	// every leap year adds 1 day
	Offset = 6 + Year + Year/4;
	// Add month offset from table
	Offset += MonthOffset[Month-1];
	// Add day
	Offset += Day;

	// If it's a leap year and before March there's no additional day yet
	if((Year%4) == 0)
		if(Month < 3)
			Offset -= 1;

	// Week day is
	Offset %= 7;

	RTCCSetWkDay(Offset);
}
#endif


/*****************************************************************************
 * Function: RTCCSetBinDay
 *
 * Preconditions: None.
 *
 * Overview: The function verifies a setting day range, translates it into
 * BCD format and writes into rtccTime_chk structure. To write the structure into
 * clock RTCCSetTime must be called.
 *
 * Input: Day binary value.
 *
 * Output: Checked BCD value in rtccTime_chk structure.
 *
 *****************************************************************************/
void RTCCSetBinDay(unsigned char Day)
{
    const char MonthDaymax[] =
                    //jan feb mar apr may jun jul aug sep oct nov dec
                    {  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    static unsigned int Daymax;
    static unsigned int Month;
    static unsigned int Year;

    Month = RTCCGetBinMonth();
    Year = RTCCGetBinYear();

    Daymax = MonthDaymax[Month-1];

    // February has one day more for a leap year
    if(Month == 2)
    if( (Year%4) == 0)
        Daymax++;

    if(Day == 0) Day = Daymax;
    if(Day > Daymax) Day = 1;
    RTCCSetDay(RTCCBin2Dec(Day));
}

/*****************************************************************************
 * Function: RTCCSetBinMonth
 *
 * Preconditions: None.
 *
 * Overview: The function verifies a setting month range, translates it into
 * BCD format and writes into rtccTime_chk structure. To write the structure into
 * clock RTCCSetTime must be called.
 *
 * Input: Month binary value.
 *
 * Output: Checked BCD value in rtccTime_chk structure.
 *
 *****************************************************************************/
void RTCCSetBinMonth(unsigned char Month)
{
    if(Month < 1)  Month = 12;
    if(Month > 12) Month = 1;
    RTCCSetMonth(RTCCBin2Dec(Month));
}

/*****************************************************************************
 * Function: RTCCSetBinYear
 *
 * Preconditions: None.
 *
 * Overview: The function verifies a setting year range, translates it into
 * BCD format and writes into rtccTime_chk structure. To write the structure into
 * clock RTCCSetTime must be called.
 *
 * Input: Year binary value.
 *
 * Output: Checked BCD value in rtccTime_chk structure.
 *
 *****************************************************************************/
void RTCCSetBinYear(unsigned char Year)
{
    if(Year == 0xff) Year = 99;
    if(Year == 100)  Year = 0;
    RTCCSetYear(RTCCBin2Dec(Year));

    // Recheck day. Leap year influences to Feb 28/29.
    RTCCSetBinDay(RTCCGetBinDay());
}

/*****************************************************************************
 * EOF
 *****************************************************************************/
